package com.iot.auth.filter;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.ObjectUtils;

import com.alibaba.fastjson.JSONObject;
import com.iot.common.core.constant.CommonConstants;
import com.iot.common.core.constant.RedisConstants;
import com.iot.common.core.constant.SecurityConstants;
import com.iot.common.core.util.Md5Util;
import com.iot.common.core.util.R;
import com.iot.common.core.util.RequestUtil;
import com.iot.common.core.util.SpringContextHolder;
import com.iot.common.core.util.WebUtils;
import com.iot.common.log.event.SysLogEvent;
import com.iot.common.log.util.LogTypeEnum;
import com.iot.common.log.util.SysLogUtils;
import com.iot.common.security.domain.SimpleUser;
import com.iot.common.security.jwt.JWTUtil;
import com.iot.manage.api.domain.SysLog;
import com.nimbusds.jose.JOSEException;
import lombok.extern.slf4j.Slf4j;

/**
 * 账号密码验证
 * 
 * @author love
 */
@Slf4j
public class SecurityUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

	private AuthenticationManager authenticationManager;
	private StringRedisTemplate redisTemplate;

	public SecurityUsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager,
			StringRedisTemplate redisTemplate) {
		this.authenticationManager = authenticationManager;
		this.redisTemplate = redisTemplate;
	}

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
	}

	@Override
	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
			Authentication authResult) throws IOException, ServletException {
		SysLog sysLog = SysLogUtils.getSysLog();
		sysLog.setTitle("登录");
		Long startTime = System.currentTimeMillis();
		SimpleUser user = (SimpleUser) authResult.getPrincipal();
		String payload = JSONObject.toJSONString(user);

		try {

			String token = JWTUtil.createToken(payload);

			log.info("登录成功:{}", user.getUsername());

			// 生成Key， 把权限放入到redis中
			String keyPrefix = RedisConstants.TOKEN_KEY_PREFIX + user.getId() + ":";
			String keySuffix = Md5Util.getMD5(token.getBytes());
			String key = keyPrefix + keySuffix;
			String authKey = key + RedisConstants.AUTH_KEY;

			redisTemplate.opsForValue().set(key, token, SecurityConstants.EXPIRE_TIME, TimeUnit.MILLISECONDS);
			redisTemplate.opsForValue().set(authKey, JSONObject.toJSONString(user.getAuthorities()),
					SecurityConstants.EXPIRE_TIME, TimeUnit.SECONDS);
			sysLog.setType(LogTypeEnum.NORMAL.getType());
			response.setHeader(SecurityConstants.TOKEN_HEADER,token);
			
			if(RequestUtil.isAjaxRequest(request)) {
				WebUtils.renderJson(response, R.ok(token));
			}else {
				// 获取请求参数中是否包含 回调地址
				// 默认跳转referer 地址
				String referer = request.getHeader(HttpHeaders.REFERER);
				if(ObjectUtils.isEmpty(referer)) {
					WebUtils.renderJson(response, R.ok(token));
				}else {
					response.sendRedirect(referer);
				}
			}
			

			
		} catch (JOSEException e) {
			sysLog.setContent("Token创建异常.");
			WebUtils.renderJson(response, R.failed(500, "Token创建异常."));
			sysLog.setType(LogTypeEnum.ERROR.getType());
		} catch (RedisConnectionFailureException e) {
			sysLog.setContent("Redis连接异常.");
			WebUtils.renderJson(response, R.failed(500, "Redis连接异常."));
			sysLog.setType(LogTypeEnum.ERROR.getType());
		}
		// 日志记录
		Long endTime = System.currentTimeMillis();
		sysLog.setTime(endTime - startTime);
		SpringContextHolder.publishEvent(new SysLogEvent(sysLog));

	}

	@Override
	protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException failed) throws IOException, ServletException {
		Long startTime = System.currentTimeMillis();
		log.error("登录失败:{}", failed.getMessage());
		SysLog sysLog = SysLogUtils.getSysLog();
		sysLog.setTitle("登录失败");
		sysLog.setType(LogTypeEnum.ERROR.getType());
		if (failed instanceof UsernameNotFoundException || failed instanceof BadCredentialsException) {
			WebUtils.renderJson(response, R.failed(CommonConstants.ERROR, "账号或密码错误."));
			sysLog.setContent("账号或密码错误.");
		} else {
			WebUtils.renderJson(response, R.failed(CommonConstants.ERROR, "登录异常."));
			sysLog.setContent(failed.getLocalizedMessage());
		}
		// 日志记录
		Long endTime = System.currentTimeMillis();
		sysLog.setTime(endTime - startTime);
		SpringContextHolder.publishEvent(new SysLogEvent(sysLog));

	}

}
